package cc.eddic.practice.concurrency.impl;

import cc.eddic.practice.concurrency.LogItem;
import cc.eddic.practice.concurrency.LogItemParser;
import lombok.extern.slf4j.Slf4j;
import lombok.val;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;

@Slf4j
public class CompressedLogItemParserImpl implements LogItemParser {
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("dd/MMM/yyyy:HH:mm:ss Z", Locale.ENGLISH);
    private static final Pattern PATTERN_LOG_LINE = Pattern.compile("(?<clientIP>.+) (?<hitMiss>.+) (?<responseTime>\\d+) \\[(?<timeZone>.+)] \"" +
            "(?<method>\\w+) (?<url>.+) (?<protocol>\\S+?)\" " +
            "(?<statusCode>\\d+) (?<trafficSize>\\d+) \"(?<referer>.*?)\" \"(?<userAgent>.*)\"", Pattern.UNICODE_CHARACTER_CLASS | Pattern.DOTALL);

    @Override
    public Optional<LogItem> parse(String line) {
        val m = PATTERN_LOG_LINE.matcher(line);
        if (m.matches()) {
            String ip = m.group("clientIP");

            String hitMiss = m.group("hitMiss");
            String responseTime = m.group("responseTime");

            LocalDateTime ldt = LocalDateTime.parse(m.group("timeZone"), DATE_TIME_FORMATTER);

            String method = m.group("method");
            String url = m.group("url");
            String path;
            if (url.contains("?")) {
                int index = url.indexOf('?');
                path = url.substring(0, index);
            } else {
                path = url;
            }

            String protocol = m.group("protocol");


            int status = Integer.parseInt(m.group("statusCode"));
            long bytes = Long.parseLong(m.group("trafficSize"));
            String referer = m.group("referer");
            String userAgent = m.group("userAgent");

            String request = null;

            Map<String, String> query = new HashMap<>();


            LogItem logItem = new LogItem(ip, ldt, request, method, path, query, protocol, status, bytes, referer, userAgent);

            return Optional.of(logItem);

        } else {
            return Optional.empty();
        }
    }

}
